#include "filemanagement.h"

fileManagement::fileManagement(const char *fileName, byte mode)
{
    this->controlledFile = NULL;

    if( ! fileName )
        this->status = S_ERROR_SYNTAX;
    else if( access(fileName, F_OK) )
        this->status = S_ERROR_N_EXIST;
    else if( (mode & MODE_W) && access(fileName, W_OK) )
        this->status = S_ERROR_DENY_W;
    else if( (mode & MODE_R) && access(fileName, R_OK) )
        this->status = S_ERROR_DENY_R;
    else
    {
        this->controlledFile = new fstream(fileName,
                ((mode & MODE_W) ? fstream::out : (std::_Ios_Openmode)0) |
                ((mode & MODE_R) ? fstream::in : (std::_Ios_Openmode)0));
        this->fileName = string(fileName);

        if( this->controlledFile->is_open() && this->controlledFile->good()
                && this->isPaste(fileName) == 0)
        {
            this->status = S_READY;
            this->patchCont = 0;
            this->setFileSize();
            this->setData();
            this->editString = string("");
            this->line = 0;
        }
        else
            this->status = S_ERROR_UNKN;
    }


}
fileManagement::~fileManagement()
{
    this->close();
}

void fileManagement::setFileSize()
{
    streampos currentPos = this->controlledFile->tellg();
    this->controlledFile->seekg(0, ios::end);
    this->fileSize = size_t(this->controlledFile->tellg());
    this->controlledFile->seekg(currentPos, ios::beg);
}

const string fileManagement::getFileName()
{
    return this->fileName;
}

unsigned int fileManagement::currentPatch()
{
    return this->patchCont;
}

byte fileManagement::currentStatus()
{
    return this->status;
}

void fileManagement::resetPatch()
{
    this->patchCont = 0;
    this->controlledFile->seekg(0, ios::beg);
}
bool fileManagement::setData()
{
    size_t size;
    size_t remainingSize = this->fileSize-this->controlledFile->tellg();

    /* Configura o tamanho dos dados */
    if(remainingSize > MAX_DATA_SIZE)
        size = MAX_DATA_SIZE;
    else if(remainingSize > 0)
    {
        size = remainingSize;
        this->status = S_EOF;
    }
    else
    {
        this->dataSize = 0; /* para evitar alguns erros */
        this->status = S_EOF;
        return false;
    }

    /* Lê os dados */
    this->controlledFile->read((char*)this->messageData, size);
    this->messageData[size] = '\0';
    this->dataSize = size;

    return this->status == S_EOF ? false : true;
}
const byte *fileManagement::currentData()
{
    return this->messageData;
}
byte fileManagement::currentDataSize()
{
    return this->dataSize;
}

const byte *fileManagement::nextData()
{
    if( this->status == S_EOF )
        return NULL;

    this->patchCont++;
    this->setData();

    return this->messageData;
}

void fileManagement::editLine(const byte *data, size_t size)
{
    this->editString += string((const char*)data, size);
}

bool fileManagement::setLine(unsigned int line)
{
    if( line > this->nLines() )
        return false;
    this->line = line;

    return true;
}

unsigned int fileManagement::nLines()
{
    streampos currentPosition = this->controlledFile->tellg();
    unsigned int lines = 0;
    this->controlledFile->seekg(0, ios::beg);

    while( this->controlledFile->good() )
        if( this->controlledFile->get() == '\n' ) lines++;

    this->controlledFile->clear();
    this->controlledFile->seekg(currentPosition, ios::beg);

    return (!lines && this->fileSize)? 1 : lines;
}

byte fileManagement::writeMode(byte mode)
{
    if( mode )
        this->wMode = mode;

    return this->wMode;
}

bool fileManagement::saveEdit()
{
    if( !this->line )
        return false;

    string command = "sed -i 'NUMs/.*/" + this->editString + "/' " + this->fileName;

    size_t position = command.find("NUM");

    if(position != string::npos)
    {
        std::stringstream numStr;
        numStr << this->line;
        command.replace(position, 3, numStr.str());
        return ! system(command.c_str());
    }

    return false;
}

bool fileManagement::append(const byte *data, size_t size)
{
    if( ! data )
    {
        this->status = S_ERROR_SYNTAX;
        return false;
    }

    this->controlledFile->seekp(0, ios::end);
    this->controlledFile->write((const char*)data, size);
    this->patchCont = this->fileSize/MAX_DATA_SIZE-1;


    if( this->controlledFile->bad() )
    {
        this->status = S_ERROR_DENY_W;
        return false;
    }
    else
    {
        this->setFileSize();
        this->patchCont = this->fileSize/MAX_DATA_SIZE-1;
        this->status = S_EOF;
    }

    return true;
}

void fileManagement::close()
{
    if( this->controlledFile && this->controlledFile->is_open() )
        this->controlledFile->close();
    else if( this->controlledFile )
        delete this->controlledFile;

    this->status = S_CLOSED;
}

int fileManagement::isPaste(const char *l)
{
    DIR *dir = opendir(l);
    int ret = 0;

    if (dir){
        ret = 1;
        closedir(dir);
    } else if (errno == ENOTDIR)
        ret = 0;
    else
        ret = -1;

    return ret;
}
